<template>
	<div class="default-main">

		<cus-form id="role-form" collapsable icon="fa fa-search" label="搜索">
			<template #title-after>
				<el-button :loading="tableLoading" icon="el-icon-Search" size="small" type="primary" @click.stop="handleSearch">
					搜索
				</el-button>
				<el-button :loading="tableLoading" icon="el-icon-Refresh" size="small" type="primary" @click.stop="resetSearch">
					重置
				</el-button>
			</template>
			<template #form>
				<el-form ref="searchForm" :model="params" label-width="auto">
					<el-row :gutter="20" justify="end">
						<el-col :span="8">
							<el-form-item label="角色编码">
								<el-input v-model="params.roleCode_like" clearable placeholder="模糊查询" @keyup.enter="handleSearch"></el-input>
							</el-form-item>
						</el-col>
						<el-col :span="8">
							<el-form-item label="角色名称">
								<el-input v-model="params.roleName_like" clearable placeholder="模糊查询" @keyup.enter="handleSearch"></el-input>
							</el-form-item>
						</el-col>
						<el-col :span="8">
							<el-form-item label="描述">
								<el-input v-model="params.description_like" clearable placeholder="模糊查询" @keyup.enter="handleSearch"></el-input>
							</el-form-item>
						</el-col>
					</el-row>
					<el-row :gutter="20" justify="start">
						<el-col :span="8">
							<el-form-item label="管理员">
								<business-code-radio v-model="params.isAdmin_eq" border code-type="roleIsAdmin" @change="handleSearch"/>
							</el-form-item>
						</el-col>
					</el-row>
				</el-form>
			</template>
		</cus-form>

		<cus-table-title id="role-table-title" icon="local-cus-role" label="角色">
			<template #after>
				<el-button v-auth="'sys-role:saveRole'" icon="el-icon-Plus" size="small" style="margin-left: 20px" type="primary" @click="toAdd">
					新增
				</el-button>
			</template>
		</cus-table-title>
		<el-table id="role-table" ref="tableRef" v-loading="tableLoading" :data="roleTableData" :header-cell-class-name="handleHeaderCellClass"
		          :max-height="tableMaxHeight" border class="cus-table" fit highlight-current-row
		          @sort-change="elTableSortChange($event, params.orderby, handleSearch)">
			<el-table-column align="center" label="序号" width="60">
				<template v-slot="scope">
					{{ initTableIndex(pageRef, scope.$index) }}
				</template>
			</el-table-column>
			<el-table-column align="center" label="角色编码" min-width="150" prop="roleCode" show-overflow-tooltip sortable="custom"></el-table-column>
			<el-table-column align="center" label="角色名称" min-width="150" prop="roleName" show-overflow-tooltip></el-table-column>
			<el-table-column align="center" label="管理员" prop="isAdmin" sortable="custom" width="100">
				<template v-slot="{row}">
					<el-tag :type="row.isAdmin ? 'success' : 'info'">{{ getBusinessCodeName('roleIsAdmin', row.isAdmin) }}</el-tag>
				</template>
			</el-table-column>
			<el-table-column align="center" label="描述" min-width="450" prop="description"></el-table-column>
			<el-table-column :label="$t('table.actions')" align="center" fixed="right" width="250">
				<template v-slot="{row}">
					<el-button v-auth="'sys-role:saveUserRole'" :loading="userRoleButtonLoading" icon="el-icon-User" size="small"
					           type="primary" @click="showUserRole(row)">用户
					</el-button>
					<el-button v-auth="'sys-authority:saveRoleAuthority'" icon="el-icon-Key" size="small" type="primary"
					           @click="toAuthPage(row)">权限
					</el-button>
					<el-dropdown style="margin-left: 10px">
						<el-button icon="el-icon-More" plain round size="small"></el-button>
						<template #dropdown>
							<el-dropdown-menu>
								<el-dropdown-item :disabled="!hasPermission('sys-role:saveRole')" icon="el-icon-Edit" @click="toUpdate(row)">
									编辑
								</el-dropdown-item>
								<el-dropdown-item :disabled="!hasPermission('sys-role:deleteRole')" icon="el-icon-Delete" @click="deleteRole(row)">
									删除
								</el-dropdown-item>
							</el-dropdown-menu>
						</template>
					</el-dropdown>
				</template>
			</el-table-column>
		</el-table>
		<cus-pagination id="role-pagination" ref="pageRef" v-model="roleTableData" v-model:loading="tableLoading" :pageSize="10" :params="params"
		                url="/system/sys-role/readOnly/pageRole"/>

		<!-- 对话框（新增、修改） -->
		<el-dialog v-model="editDialogVisible" :close-on-click-modal="false" :title="dialogTitle" append-to-body center class="cus-dialog" destroy-on-close
		           draggable width="50%">
			<el-form ref="editFormRef" :model="role" :rules="rules" label-width="100">
				<el-row :gutter="20" justify="space-between">
					<el-col :span="12">
						<el-form-item label="角色编码" prop="roleCode">
							<el-input v-model="role.roleCode" clearable/>
						</el-form-item>
					</el-col>
					<el-col :span="12">
						<el-form-item label="角色名称" prop="roleName">
							<el-input v-model="role.roleName" clearable/>
						</el-form-item>
					</el-col>
				</el-row>
				<el-form-item label="管理员" prop="isAdmin">
					<business-code-switch v-model="role.isAdmin" :active-value="1" :inactive-value="0" :show-text="false" code-type="roleIsAdmin"/>
				</el-form-item>
				<el-form-item label="描述" prop="description">
					<el-input v-model="role.description" :autosize="{ minRows: 4, maxRows: 4}" clearable type="textarea"/>
				</el-form-item>
			</el-form>
			<template #footer>
				<el-button v-auth="'sys-role:saveRole'" :loading="saveRoleButtonLoading" icon="el-icon-CircleCheck" type="primary" @click="save">
					保存
				</el-button>
				<el-button icon="el-icon-CircleClose" type="warning" @click="editDialogVisible = false">
					取消
				</el-button>
			</template>
		</el-dialog>

		<!--对话框（分配用户）-->
		<el-dialog v-model="userRoleDialogVisible" :close-on-click-modal="false" :title="userRoleDialogTitle" append-to-body center class="cus-dialog"
		           destroy-on-close draggable
		           width="700">
			<el-transfer v-model="selectedUserIdList" :button-texts="['移出', '加入']" :data="allUserList"
			             :props="transferProps" :titles="['未分配', '已分配']" class="cus-center" filter-placeholder="搜索"
			             filterable/>
			<template #footer>
				<el-button v-auth="'sys-role:saveUserRole'" :loading="saveUserRoleButtonLoading" icon="el-icon-CircleCheck"
				           type="primary" @click="saveUserRole">
					保存
				</el-button>
				<el-button icon="el-icon-CircleClose" type="warning" @click="userRoleDialogVisible = false">
					取消
				</el-button>
			</template>
		</el-dialog>

	</div>
</template>

<script lang="ts" name="RoleManagement" setup>

import type {TransferPropsAlias} from 'element-plus/es/components/transfer/src/transfer'
import {deleteRoleApi, getUserRoleInfoApi, saveRoleApi, saveUserRoleApi} from '@/api/system/role.api'
import {nextTick, onActivated, onMounted, reactive, ref} from 'vue'
import type {FormInstance, FormRules} from 'element-plus'
import {ElMessageBox, type TableColumnCtx} from 'element-plus'
import {elTableHeaderCellClassName, elTableSortChange, exist, focusFormErrorElement, getBusinessCodeName, initTableIndex, messageSuccess} from '@/utils/commonUtil'
import {useI18n} from 'vue-i18n'
import {routePush, updateDynamicRoutes} from '@/utils/routeUtil'
import {useGlobalProperties} from '@/utils/vue3Util'
import {useAuthorityStore} from '@/stores/modules/authority.store'
import CusTableTitle from '@/components/cus-table-title.vue'
import CusPagination from '@/components/cus-pagination.vue'
import {cloneDeep, debounce, type DebouncedFunc, remove} from 'lodash-es'
import {calcMaxHeight} from '@/utils/layoutUtil'
import {useEventListener} from '@vueuse/core'
import {onBeforeRouteLeave, useRoute} from 'vue-router'
import BusinessCodeSwitch from '@/components/business-code-switch.vue'
import BusinessCodeRadio from '@/components/business-code-radio.vue'
import {useUserStore} from '@/stores/modules/user.store'
import router from '@/router'
import {homeRoute} from '@/router/static'
import {useNavTabsStore} from '@/stores/modules/navTabs.store'
import {hasPermission} from '@/utils/authUtil'
import CusForm from '@/components/cus-form.vue'

const authorityStore = useAuthorityStore(),
		userStore = useUserStore(),
		navTabsStore = useNavTabsStore(),
		globalProperties = useGlobalProperties(),
		route = useRoute(),
		{t} = useI18n(),
		transferProps: TransferPropsAlias = {
			key: 'userId',
			label: 'displayName'
		},
		tableMaxHeight = ref<number>(800),
		params = reactive({
			roleCode_like: undefined,
			roleName_like: undefined,
			isAdmin_eq: undefined,
			description_like: undefined,
			orderby: []
		}),
		roleTableData = ref<SysRole[]>([]),
		userRoleButtonLoading = ref(false),
		tableLoading = ref(false),
		role = reactive<SysRole>({
			id: undefined,
			roleCode: undefined,
			roleName: undefined,
			isAdmin: undefined,
			description: undefined,
			createTime: undefined,
			updateTime: undefined
		}),
		dialogTitle = ref<string>(),
		userRoleDialogTitle = ref<string>(),
		saveRoleButtonLoading = ref(false),
		saveUserRoleButtonLoading = ref(false),
		editDialogVisible = ref(false),
		userRoleDialogVisible = ref(false),
		pageRef = ref(),
		tableRef = ref(),
		editFormRef = ref<FormInstance>(),
		rules = reactive<FormRules>({
			roleCode: [
				{required: true, message: '请输入角色编码', trigger: 'change'}
			],
			roleName: [
				{required: true, message: '请输入角色名称', trigger: 'change'}
			],
			isAdmin: [
				{required: true, message: '请选择是否为管理员', trigger: 'change'}
			]
		}),
		allUserList = ref<TransferItem[]>([]),
		selectedUserIdList = ref<TransferItem['userId'][]>([]),
		editingRoleId = ref<number>(),
		getTableMaxHeight: DebouncedFunc<() => typeof getTableMaxHeight> = debounce(() => {
			tableMaxHeight.value = calcMaxHeight('#role-form', '#role-table-title', '#role-pagination')
			return getTableMaxHeight
		}, 100, {
			leading: true,
			trailing: false,
			maxWait: 100
		}),
		handleHeaderCellClass = (args: { rows: SysRole[], column: TableColumnCtx<SysRole>, rowIndex: number, columnIndex: number }) => {
			elTableHeaderCellClassName(args, params.orderby)
		},
		handleSearch = () => {
			pageRef.value.reload()
		},
		resetParams = () => {
			params.roleCode_like = undefined
			params.roleName_like = undefined
			params.isAdmin_eq = undefined
			params.description_like = undefined
			params.orderby = []
			// 清除多列的排序状态
			for (const column of tableRef.value?.store.states.columns.value) {
				column.order = null
			}
		},
		resetSearch = () => {
			resetParams()
			handleSearch()
		},
		resetRole = () => {
			role.id = undefined
			role.roleCode = undefined
			role.roleName = undefined
			role.isAdmin = undefined
			role.description = undefined
			role.createTime = undefined
			role.updateTime = undefined
		},
		toAdd = () => {
			resetRole()
			editDialogVisible.value = true
			dialogTitle.value = '新增角色'
			nextTick(() => {
				editFormRef.value!.clearValidate()
			})
		},
		save = () => {
			editFormRef.value!.validate(isValid => {
				if (isValid) {
					saveRoleButtonLoading.value = true
					saveRoleApi(role).then(() => {
						if (role.id) {
							messageSuccess(t('successMessage.update'))
						} else {
							messageSuccess(t('successMessage.add'))
						}
						editDialogVisible.value = false
						pageRef.value.buildData()
					}).finally(() => {
						saveRoleButtonLoading.value = false
					})
				} else {
					focusFormErrorElement()
				}
			})
		},
		toUpdate = (row: SysRole) => {
			resetRole()
			Object.assign(role, JSON.parse(JSON.stringify(row)))
			dialogTitle.value = '编辑角色信息'
			editDialogVisible.value = true
		},
		deleteRole = (row: SysRole) => {
			ElMessageBox.confirm(`${row.roleCode}（${row.roleName}）`, '删除该角色？', {
				confirmButtonText: '确定',
				cancelButtonText: '取消',
				type: 'warning',
				draggable: true
			}).then(() => {
				const loading = globalProperties.$loading()
				deleteRoleApi(row.id!).then(() => {
					messageSuccess(t('successMessage.delete'))
					pageRef.value.buildData()
				}).finally(() => {
					loading.close()
				})
			}).catch(() => {
			})
		},
		toAuthPage = (row: SysRole) => {
			authorityStore.editingRole = cloneDeep(row)
			routePush({name: 'AuthorityManagement'})
		},
		showUserRole = (row: SysRole) => {
			userRoleButtonLoading.value = true
			getUserRoleInfoApi(row.id!).then(response => {
				allUserList.value = []
				for (const user of response.data.userList) {
					allUserList.value.push({
						userId: user.id!,
						displayName: user.nickname
					})
				}
				selectedUserIdList.value = response.data.identifiedUserIdList
				editingRoleId.value = row.id
				userRoleDialogTitle.value = `角色：${row.roleCode} - ${row.roleName}`
				userRoleDialogVisible.value = true
			}).finally(() => {
				userRoleButtonLoading.value = false
			})
		},
		saveUserRole = () => {
			saveUserRoleButtonLoading.value = true
			saveUserRoleApi({
				roleId: editingRoleId.value!,
				userIdList: selectedUserIdList.value
			}).then(response => {
				// 如果改变了自身的角色，则需要更新token和userStore中的roleCodes和roleNames
				userStore.modifyToken(response.data?.token, response.data?.expire)
				const editingRole = roleTableData.value.find(role => role.id === editingRoleId.value)!
				const roleRemoved = userStore.roleCodes.includes(editingRole.roleCode!) && !selectedUserIdList.value.includes(userStore.userId!)
				const roleAdded = !userStore.roleCodes.includes(editingRole.roleCode!) && selectedUserIdList.value.includes(userStore.userId!)
				if (roleRemoved || roleAdded) {
					// 原有角色被移除
					if (roleRemoved) {
						remove(userStore.roleCodes, roleCode => roleCode === editingRole.roleCode!)
						remove(userStore.roleNames, roleName => roleName === editingRole.roleName!)
					}
					// 新角色被添加
					else if (roleAdded) {
						userStore.roleCodes.push(editingRole.roleCode!)
						userStore.roleNames.push(editingRole.roleName!)
					}
					const isAdmin = response.data?.isAdmin
					if (exist(isAdmin)) {
						userStore.isAdmin = isAdmin
					}
					const buttons = response.data?.buttons
					if (buttons) {
						userStore.buttons = buttons
					}
					const menus = response.data?.menus
					if (menus) {
						userStore.dynamicMenus = menus
						// 更新动态路由
						updateDynamicRoutes()
						// 初始化菜单
						userStore.generateMenu()
						// 关闭所有没有权限的标签页
						navTabsStore.retainTheseTabs(menuVo => router.getRoutes().some(item => item.path === menuVo.meta.fullPath))
						// 如果当前路由已不存在，则跳转到首页
						if (!router.getRoutes().some(item => item.path === route.path)) {
							routePush(homeRoute)
							return
						}
					}
				}
				userRoleDialogVisible.value = false
				messageSuccess(t('successMessage.save'))
			}).finally(() => {
				saveUserRoleButtonLoading.value = false
			})
		}

onMounted(() => {
	useEventListener(window, 'resize', getTableMaxHeight()!)
})

// 该页面开启缓存且首次或后续进入时执行，刷新页面不执行
onActivated(() => {
	useEventListener(window, 'resize', getTableMaxHeight()!)
})

onBeforeRouteLeave(() => {
	window.removeEventListener('resize', getTableMaxHeight)
})

</script>

<style lang="scss" scoped>
.transfer-footer {
	margin-left: 15px;
	padding: 6px 5px;
}
</style>
